package com.devilvan.betrice.proxy;

import com.devilvan.betrice.exception.BetriceException;
import com.devilvan.betrice.exception.constant.BetriceExceptionConstant;
import com.devilvan.betrice.proxy.pojo.BetriceProxyDto;
import com.devilvan.betrice.proxy.pojo.ProxyPo;
import com.devilvan.betrice.proxy.service.ProxyService;
import com.devilvan.betrice.util.UCopy;
import org.apache.http.HttpHost;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.HttpRequestBase;
import org.springframework.scheduling.annotation.Async;

import javax.annotation.Resource;
import java.util.List;
import java.util.Optional;

/**
 * @author Evad.Wu
 * @Description Http代理 抽象类（使用模板模式）
 * @date 2022-08-12
 */
//@Component
public abstract class BetriceHttpProxy {
    @Resource(name = "proxyServiceImpl")
    private ProxyService proxyService;

    /**
     * 被代理对象
     */
    private HttpRequestBase proxiedRequest;
    /**
     * 代理对象的IP+端口
     */
    public List<HttpHost> proxyHostList;

    /**
     * 模板执行器
     *
     * @return 配置代理后的请求
     */
    public List<BetriceProxyDto> run() {
        proxiedRequest = Optional.ofNullable(proxiedRequest)
                .orElseThrow(() -> new BetriceException(BetriceExceptionConstant.PROXIED_IS_NULL_EXP.getMessage()));
        String json = requestProxy();
        List<BetriceProxyDto> betriceProxyDto = Optional.ofNullable(parseRequestJson(json))
                .orElseThrow(() -> new BetriceException(BetriceExceptionConstant.PROXY_INFO_INCORRECT_EXP.getMessage()));
        setProxyHost(proxiedRequest, betriceProxyDto);
        executeSaveProxy(betriceProxyDto);
        return betriceProxyDto;
    }

    /**
     * 步骤1：给request赋值，将获取请求的权限交给子类
     *
     * @return 子类获取的请求
     */
    public HttpRequestBase getProxiedRequest() {
        return proxiedRequest;
    }

    /**
     * 步骤2：请求代理网站，获取单个代理地址
     *
     * @return 返回的json串
     */
    public abstract String requestProxy();

    /**
     * 步骤3：将请求得到的代理信息报文进行解析
     *
     * @param requestJson 请求得到的代理信息报文
     * @return 得到代理传输对象
     */
    public abstract List<BetriceProxyDto> parseRequestJson(String requestJson);

    /**
     * 步骤4：为请求设置代理host
     *
     * @param request             需要代理的请求
     * @param betriceProxyDtoList 代理传输对象集合
     */
    public abstract void setProxyHost(HttpRequestBase request, List<BetriceProxyDto> betriceProxyDtoList);

    /**
     * 步骤4：需要代理的情境下才有结果，即返回代理对象的信息
     *
     * @return 代理对象的信息
     */
    public List<HttpHost> getProxyHost() {
        return proxyHostList;
    }

    /**
     * 步骤5：请求代理得到的代理信息，还需要配合证书才能用来请求其他地址
     *
     * @param betriceProxyDto 代理传输对象
     * @return 证书
     */
    public abstract CredentialsProvider getCredentialsProvider(BetriceProxyDto betriceProxyDto);

    /**
     * 步骤6：线程保存请求到的代理IP、端口
     */
    @Async(value = "threadPoolExecutor")
    public void executeSaveProxy(List<BetriceProxyDto> betriceProxyDtoList) {
        List<ProxyPo> proxyPoList = betriceProxyDtoList.stream().map(proxyVo -> {
            ProxyPo proxyPo = new ProxyPo();
            UCopy.fullCopy(proxyVo, proxyPo);
            return proxyPo;
        }).toList();
        proxyService.saveBatchProxyPo(proxyPoList);
    }
}
